﻿using DataType;
using DataType.Actions;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.Operators;
using OprsSimulator.OprAttributes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using static ActionsJudge.ShootJudge;
using static System.Collections.Specialized.BitVector32;

namespace ActionsJudge
{
    internal static class ShootJudge
    {
        /// <summary>
        /// 本方法应该输出2个结果ShootedJudgeResult和ShootingJudgeResult
        /// </summary>
        /// <param name="act"></param>
        /// <param name="oprs"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        public static List<IJudgeResult> ToJudge(IBasicAction act, List<IOperator> oprs, Map map, ShootJudgeTable shootJudgeTable)
        {
            List<IJudgeResult> judgeResults = new List<IJudgeResult>();

            // 判断数据
            ShootAction action = (ShootAction)act;
            IOperator opr = null;
            foreach (IOperator oper in oprs)
            {
                if (oper.ObjID == action.ObjID)
                {
                    opr = oper;
                    break;
                }
            }
            if (opr == null)
            {
                Trace.TraceWarning($"无效裁决：射击算子不存在");
                return new List<IJudgeResult>();
            }
            IOperator enemy = null;
            foreach (IOperator oper in oprs)
            {
                if (oper.ObjID == action.TargetObjID)
                {
                    enemy = oper;
                    break;
                }
            }
            if(enemy == null)
            {
                Trace.TraceWarning($"无效裁决：目标算子不存在");
                return new List<IJudgeResult>();
            }
            if (!typeof(ICommonAttris).IsAssignableFrom(opr.GetType()) || 
                !typeof(IAttackAttris).IsAssignableFrom(opr.GetType()) || 
                !typeof(IMoveAttris).IsAssignableFrom(opr.GetType()) || 
                !typeof(IStateAttris).IsAssignableFrom(opr.GetType()) ||
                 !typeof(IReconnaissanceAttris).IsAssignableFrom(opr.GetType()))
            {
                Trace.TraceWarning($"无效裁决：攻击算子{action.ObjID}不具有发起攻击所需要的全部属性");
                return new List<IJudgeResult>();
            }
            if (!typeof(ICommonAttris).IsAssignableFrom(enemy.GetType()) ||
                !typeof(IDefendAttris).IsAssignableFrom(enemy.GetType()) ||
                !typeof(IMoveAttris).IsAssignableFrom(enemy.GetType()) ||
                !typeof(IStateAttris).IsAssignableFrom(enemy.GetType()))
            {
                Trace.TraceWarning($"无效裁决：被攻击算子{action.TargetObjID}不具有被攻击所需要的全部属性");
                return new List<IJudgeResult>();
            }

            //取得属性
            Dictionary<BulletType, int> remain_bullet_nums = (Dictionary<BulletType, int>)opr.GetType().GetProperty("RemainBulletNums").GetValue(opr);
            Color color = (Color)opr.GetType().GetProperty("Color").GetValue(opr);
            int weapon_cool_time = (int)opr.GetType().GetProperty("WeaponCoolTime").GetValue(opr);
            int weapon_unfold_time = (int)opr.GetType().GetProperty("WeaponUnfoldTime").GetValue(opr);
            int weapon_unfold_state = (int)opr.GetType().GetProperty("WeaponUnfoldState").GetValue(opr);
            MoveStateType move_state = (MoveStateType)opr.GetType().GetProperty("MoveState").GetValue(opr);
            MoveStateType target_state = (MoveStateType)opr.GetType().GetProperty("TargetState").GetValue(opr); 
            int change_state_remain_time = (int)opr.GetType().GetProperty("ChangeStateRemainTime").GetValue(opr);
            List<WeaponType> carry_weapon_ids = (List<WeaponType>)opr.GetType().GetProperty("CarryWeaponIDs").GetValue(opr);
            int cur_hex = (int)opr.GetType().GetProperty("CurHex").GetValue(opr);
            int blood = (int)opr.GetType().GetProperty("Blood").GetValue(opr);
            bool keep = (bool)opr.GetType().GetProperty("Keep").GetValue(opr);
            bool stop = (bool)opr.GetType().GetProperty("Stop").GetValue(opr);
            OprSubType sub_type = (OprSubType)opr.GetType().GetProperty("Subtype").GetValue(opr);
            OprType type = (OprType)opr.GetType().GetProperty("Type").GetValue(opr);
            bool moveShootAbility = (bool)opr.GetType().GetProperty("A1").GetValue(opr);  // 行进间射击能力
            Dictionary<OprSubType, int> observe_distance = (Dictionary<OprSubType, int>)opr.GetType().GetProperty("ObserveDistance").GetValue(opr);
            int speed = (int)opr.GetType().GetProperty("Speed").GetValue(opr);
            int get_on_remain_time = (int)opr.GetType().GetProperty("GetOnRemainTime").GetValue(opr);
            int get_off_remain_time = (int)opr.GetType().GetProperty("GetOffRemainTime").GetValue(opr);

            Color enemy_color = (Color)enemy.GetType().GetProperty("Color").GetValue(enemy);
            int enemy_blood = (int)enemy.GetType().GetProperty("Blood").GetValue(enemy);
            int enemy_cur_hex = (int)enemy.GetType().GetProperty("CurHex").GetValue(enemy);
            bool enemy_stack = (bool)enemy.GetType().GetProperty("Stack").GetValue(enemy);
            MoveStateType enemy_move_state = (MoveStateType)enemy.GetType().GetProperty("MoveState").GetValue(enemy);
            int enemy_speed = (int)enemy.GetType().GetProperty("Speed").GetValue(enemy);
            ArmorType enemy_armor = (ArmorType)enemy.GetType().GetProperty("Armor").GetValue(enemy);
            OprSubType enemy_sub_type = (OprSubType)enemy.GetType().GetProperty("Subtype").GetValue(enemy);
            OprType enemy_type = (OprType)enemy.GetType().GetProperty("Type").GetValue(enemy);
            if (enemy_type != OprType.Vehicle && enemy_type != OprType.Infantry)  // 直瞄射击的目标只能是车辆或步兵
            {
                Trace.TraceWarning($"无效裁决：目标算子不是车辆或步兵");
                return new List<IJudgeResult>();
            }
            //判断能否射击
            bool flag_shoot = true;
            if (action.Type != ActionType.Shoot)
            {
                Trace.TraceWarning($"无效裁决：算子行动类型不是射击");
                return new List<IJudgeResult>();
            }
            // 需要先判定使用的是什么类型弹药，根据武器类型判断
            BulletType bulletType = shootJudgeTable.GetWeapon(action.WeaponID).Bullet;
            if (remain_bullet_nums[bulletType] <= 0)
            {
                Trace.TraceWarning($"无效裁决：没有可用弹药");
                return new List<IJudgeResult>();
            }
            if (color == enemy_color)
            {
                Trace.TraceWarning($"无效裁决：射击算子与目标算子是同一方");
                return new List<IJudgeResult>();
            }
            if (weapon_cool_time > 0)
            {
                Trace.TraceWarning($"无效裁决：武器处于冷却中");
                return new List<IJudgeResult>();
            }
            if (weapon_unfold_time > 0) // 武器正在展开或折叠
            {
                Trace.TraceWarning($"无效裁决：武器正在展开或折叠");
                return new List<IJudgeResult>();
            }
            if (weapon_unfold_state == 0) // 武器处于锁定状态
            {
                Trace.TraceWarning($"无效裁决：武器处于锁定状态");
                return new List<IJudgeResult>();
            }
            if (move_state == MoveStateType.March)  // 行军状态不可射击
            {
                Trace.TraceWarning($"无效裁决：射击算子处于行军状态");
                return new List<IJudgeResult>();
            }
            if (target_state == MoveStateType.March && change_state_remain_time > 0)  // 行军状态转换过程中
            {
                Trace.TraceWarning($"无效裁决：射击算子处于行军状态转换过程中");
                return new List<IJudgeResult>();
            }
            if (!moveShootAbility && target_state == MoveStateType.Shelt && change_state_remain_time > 0)
            {
                Trace.TraceWarning($"无效裁决：无行进间射击能力的算子处于掩蔽状态转换过程中，不能射击");
                return new List<IJudgeResult>();
            }
            if (!moveShootAbility && !stop)
            {
                Trace.TraceWarning($"无效裁决：无行进间射击能力的算子不处于静止状态，不能射击");
                return new List<IJudgeResult>();
            }
            else if (action.WeaponID != WeaponType.MediumDirectGun && action.WeaponID != WeaponType.LargeDirectGun)
            {
                Trace.TraceWarning($"无效裁决：使用的不是坦克主炮（大号、中号直瞄炮），不可行进间射击");
                return new List<IJudgeResult>();
            }
            if (!carry_weapon_ids.Contains(action.WeaponID))
            {
                Trace.TraceWarning($"无效裁决：射击算子未装配该行动的武器");
                return new List<IJudgeResult>();
            }
            if (get_on_remain_time > 0 || get_off_remain_time > 0)
            {
                Trace.TraceWarning($"无效裁决：算子正在上车或者下车,不能射击");
                return new List<IJudgeResult>();
            }
            if (sub_type == OprSubType.Infantry && keep)
            {
                Trace.TraceWarning($"无效裁决：人员被压制时不能射击");
                return new List<IJudgeResult>();
            }
            bool can_see = map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_cur_hex, enemy_sub_type, observe_distance, enemy_move_state);
            int distance = map.GetDistance(cur_hex, enemy_cur_hex);
            int attack_level = shootJudgeTable.CalcAttackLevel(can_see, remain_bullet_nums, action.WeaponID, enemy_type, distance, blood);
            if (attack_level < 0)
            {
                Trace.TraceWarning($"无效裁决：无效射击");
                return new List<IJudgeResult>();
            }
            if (enemy_blood <= 0)
            {
                Trace.TraceWarning($"无效裁决：射击目标{action.TargetObjID}血量为零");
                return new List<IJudgeResult>();
            }
            
            //计算裁决结果

            //int weapon_id = action.WeaponID;

            //int attack_level = CalcAttackLevel(opr, enemy, action.WeaponID, mapCalc);

            // 计算高度差修正
            int elev_rect;
            int elev_diff = -(map[cur_hex / 100, cur_hex % 100].elev -
                map[enemy_cur_hex / 100, enemy_cur_hex % 100].elev) / map.ElevGrade;
            if (elev_diff > 8) elev_diff = 8;
            if (elev_diff <= 0 | distance > 12) elev_rect = 0;              //      高打低 或者 距离远  不修正
            else
            {
                elev_rect = shootJudgeTable.GetElevRect(elev_diff, distance);
            }
            if (attack_level >= -elev_rect) attack_level += elev_rect;
            else attack_level = 0;

            int random1, random2, random2_rect, rect_damage, damage, ori_damage;
            if (attack_level <= 0)
            {
                random1 = -1;
                random2 = -1;
                random2_rect = -1;
                ori_damage = 0;
                rect_damage = 0;
                damage = -1;
            }
            else
            {
                if (enemy_type == OprType.Vehicle)
                {
                    // 计算origin_damage
                    Random random = new Random();
                    int r11 = random.Next(1, 7);
                    int r12 = random.Next(1, 7);
                    random1 = r11 + r12;            // 2到12 随机数
                    if (random1 < 2) random1 = 2;
                    if (random1 > 12) random1 = 12;

                    bool flag_keep = false;
                    if(action.WeaponID == WeaponType.InfantryLightWeapon)
                    {
                        //直瞄武器对人员/步兵轻武器对车辆战斗结果表
                        ori_damage = shootJudgeTable.GetToInfantryOriDamageTab(random1, attack_level);
                    }
                    else
                    {
                        int ori_damage_row = shootJudgeTable.GetOriDamageTabRow(blood, attack_level);
                        ori_damage = shootJudgeTable.GetOriDamage(ori_damage_row, random1);
                    }
                    if (ori_damage == -1)
                    {
                        flag_keep = true;
                        ori_damage = 0;
                    }

                    // 计算随机数2修正值random2_rect
                    int val = 0;
                    if (keep) val -= 1;
                    if (speed > 0) val -= 1;
                    if (sub_type == OprSubType.Tank &&  // 如果坦克算子在水上地形
                        map[cur_hex / 100, cur_hex % 100].cond == TerrainType.River)
                    {
                        val -= 1;
                    }
                    if (map[enemy_cur_hex / 100, enemy_cur_hex % 100].cond == TerrainType.City) val -= 1;
                    if (map[enemy_cur_hex / 100, enemy_cur_hex % 100].cond == TerrainType.Forest) val -= 2;
                    if (map[enemy_cur_hex / 100, enemy_cur_hex % 100].cond == TerrainType.River) val -= 2;
                    if (enemy_move_state == MoveStateType.Shelt) val -= 2;
                    if (enemy_speed > 0) val -= 2;
                    if (enemy_stack) val += 2;
                    if (enemy_move_state == MoveStateType.March) val += 4;

                    int r21 = random.Next(1, 7);
                    int r22 = random.Next(1, 7);
                    random2 = r21 + r22;
                    random2_rect = random2 + val;

                    // 计算最终战损damage
                    int random2_rect_ind;
                    if (random2_rect <= -3) random2_rect_ind = -3;
                    else if (random2_rect >= 12) random2_rect_ind = 12;
                    else random2_rect_ind = random2_rect;

                    rect_damage = shootJudgeTable.GetDamageRect(enemy_armor, random2_rect_ind);

                    damage = ori_damage + rect_damage;
                    if (damage == 0)
                    {
                        if (!flag_keep)
                        {
                            damage = -1;
                        }
                    }
                }
                else  // 目标算子是步兵的情况
                {
                    // 计算origin_damage
                    Random random = new Random();
                    int r11 = random.Next(1, 7);
                    int r12 = random.Next(1, 7);
                    random1 = r11 + r12;
                    if (random1 < 2) random1 = 2;
                    if (random1 > 12) random1 = 12;

                    ori_damage = shootJudgeTable.GetToInfantryOriDamageTab(random1, attack_level);
                    bool flag_keep = false;
                    if(ori_damage == -1)
                    {
                        flag_keep = true;
                        ori_damage = 0;
                    }

                    // 计算随机数2修正值random2_rect
                    int val = 0;
                    if (keep) val -= 1;
                    if (speed > 0) val -= 1;
                    if (map[enemy_cur_hex / 100, enemy_cur_hex % 100].cond == TerrainType.City) val -= 1;
                    if (map[enemy_cur_hex / 100, enemy_cur_hex % 100].cond == TerrainType.Forest) val -= 2;
                    if (enemy_move_state == MoveStateType.Shelt) val -= 2;
                    if (enemy_speed > 0) val -= 2;
                    if (enemy_stack) val += 2;
                    if (enemy_move_state == MoveStateType.March) val += 4;

                    int r21 = random.Next(1, 7);
                    int r22 = random.Next(1, 7);
                    random2 = r21 + r22;
                    random2_rect = random2 + val;

                    // 计算最终战损damage
                    int random2_rect_ind;
                    if (random2_rect < 0) random2_rect_ind = 0;
                    else if (random2_rect > 8) random2_rect_ind = 8;
                    else random2_rect_ind = random2_rect;

                    rect_damage = shootJudgeTable.GetToInfantryDamageRect(random2_rect_ind);

                    damage = ori_damage + rect_damage;
                    if (damage == 0)
                    {
                        if (!flag_keep)
                        {
                            damage = -1;
                        }
                    }
                }
            }

            // 根据上面得到的结果修改judge_info信息
            if (damage < 0) flag_shoot = false;

            ShootingJudgeResult shootingJudgeResult = new ShootingJudgeResult(
                action.ObjID, flag_shoot, bulletType, attack_level, blood, opr.ObjID, color, sub_type, damage, distance, elev_diff, ori_damage, random1, random2, random2_rect, rect_damage, enemy_color, enemy.ObjID, enemy_sub_type, action.WeaponID
                );
            //ShootedJudgeResult shootedJudgeResult = new ShootedJudgeResult(
            //    action.ObjID, flag_shoot, attack_level, blood, opr.ObjID, color, sub_type, damage, distance, elev_diff, ori_damage, random1, random2, random2_rect, rect_damage, enemy_color, enemy.ObjID, enemy_sub_type, action.WeaponID
            //    );

            judgeResults.Add( shootingJudgeResult );
            //judgeResults.Add( shootedJudgeResult );

            return judgeResults;
        }
    }
}
